package lhxia.translater.http.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;

import lhxia.translater.http.server.ThreadPool.WokerThread;
import lhxia.translater.http.server.ThreadPool.WokerThread.Attach;

public class HttpServer {
	
	public static final String TAG = HttpServer.class.getName();
	private ServerSocketChannel serverChannel;
	
	public void start(int port) throws IOException{
		
		System.setProperty("java.net.preferIPv6Addresses", "false");
		
		serverChannel = ServerSocketChannel.open();
		serverChannel.socket().bind(new InetSocketAddress("192.168.1.5", port));
		
		serverChannel.configureBlocking(false);
		Selector selector = Selector.open();
		serverChannel.register(selector, SelectionKey.OP_ACCEPT);

		Set<SelectionKey> keys = null;
		Iterator<SelectionKey> keysIt = null;
		SelectionKey curKey = null;;
		
		int connectCount = 0;
		while(true){
			selector.select();
			keys = selector.selectedKeys();
			keysIt = keys.iterator();
			ServerProcessor processor = new ServerProcessor();;
			SelectionKey newKey = null;
			while(keysIt.hasNext()){
				curKey = keysIt.next();
				keysIt.remove();
//				Log.d(TAG, "a key " + curKey);
				try{
					if(curKey.isAcceptable()){
						ServerSocketChannel serverChannel = (ServerSocketChannel) curKey.channel();
						SocketChannel newChanel = serverChannel.accept();
						newChanel.configureBlocking(false);
					
						newKey = newChanel.register(selector, SelectionKey.OP_READ);
						
						processor.onNewConnection(newChanel, newKey);
						connectCount++;
					}else if(curKey.isReadable()){
						if(!processor.onRead((SocketChannel) curKey.channel(), curKey)){
							throw new Exception("data error.");
						}
//						newKey = ((SocketChannel) curKey.channel()).register(selector, SelectionKey.OP_READ);
//						newKey.attach(processor);
					}
				}catch (Exception e) {
					e.printStackTrace();
					curKey.channel().close();
					curKey.cancel();
					connectCount--;
					processor.onDisconnected((SocketChannel) curKey.channel(), curKey);
					
				}
			}
		}
	}
	
	public void stop(){
		if(serverChannel != null){
			try {
				serverChannel.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static class ServerAttach {
		WokerThread thread;
		SocketChannel connection;
		SelectionKey keys;
		private Attach att;
		
		private Pipe pip;
		public ServerAttach(Pipe pip, WokerThread thread, Attach att, SocketChannel connection, SelectionKey keys) {
			super();
			this.thread = thread;
			this.connection = connection;
			this.keys = keys;
			this.att = att;
			this.pip = pip;
		}
		public WokerThread getThread() {
			return thread;
		}
		public SocketChannel getConnection() {
			return connection;
		}
		public SelectionKey getKeys() {
			return keys;
		}
		public Attach getAtt() {
			return att;
		}
		public Pipe getPip() {
			return pip;
		}
	}
}